package main

import (
	"database/sql"
	"encoding/json"
	"reflect"

	"test.com/fusion"
	"test.com/worlddb"
)

type questDialogTableRow struct {
	QuestTypeID uint32 `json:"questTypeID"`
	QuestName   string `json:"questName"`
	QuestDesc   string `json:"questDesc"`
}

func getAllQuest4DialogTable(db *sql.DB) ([]*questDialogTableRow, error) {
	questNames, err := getAllKeyI18Ns(db,
		"quest_prototype", "questTypeID", worlddb.STRING_TEXT_TYPE_QUEST_NAME)
	if err != nil {
		return nil, err
	}
	questDescs, err := getAllKeyI18Ns(db,
		"quest_prototype", "questTypeID", worlddb.STRING_TEXT_TYPE_QUEST_DESC)
	if err != nil {
		return nil, err
	}
	var questRows []*questDialogTableRow
	for questID, questName := range questNames {
		questDesc := questDescs[questID]
		questRows = append(questRows,
			&questDialogTableRow{questID, questName, questDesc})
	}
	return questRows, nil
}

func getAllQuestNames(db *sql.DB) (map[uint32]string, error) {
	return getAllKeyI18Ns(db,
		"quest_prototype", "questTypeID", worlddb.STRING_TEXT_TYPE_QUEST_NAME)
}

func getQuestInfo(db *sql.DB, questID uint32) (*worlddb.QuestPrototype, error) {
	var questInfo *worlddb.QuestPrototype
	questInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(questInfo), "`questTypeID`=?", questID)
	if err != nil {
		return nil, err
	}
	if questInfoVals.Len() < 1 {
		return nil, sql.ErrNoRows
	}
	return questInfoVals.Index(0).Interface().(*worlddb.QuestPrototype), nil
}

func getQuestInstanceJsonData(db *sql.DB, questID uint32) ([]byte, error) {
	var err error
	var questProto questWebPrototype
	questProto.QuestName, err =
		getI18N(db, worlddb.STRING_TEXT_TYPE_QUEST_NAME, questID)
	if err != nil && err != sql.ErrNoRows {
		return nil, err
	}
	questProto.QuestDesc, err =
		getI18N(db, worlddb.STRING_TEXT_TYPE_QUEST_DESC, questID)
	if err != nil && err != sql.ErrNoRows {
		return nil, err
	}
	questProto.QuestIntro, err =
		getI18N(db, worlddb.STRING_TEXT_TYPE_QUEST_INTRO, questID)
	if err != nil && err != sql.ErrNoRows {
		return nil, err
	}
	questProto.QuestDone, err =
		getI18N(db, worlddb.STRING_TEXT_TYPE_QUEST_DONE, questID)
	if err != nil && err != sql.ErrNoRows {
		return nil, err
	}
	questProto.QuestNotDone, err =
		getI18N(db, worlddb.STRING_TEXT_TYPE_QUEST_NOT_DONE, questID)
	if err != nil && err != sql.ErrNoRows {
		return nil, err
	}
	questProto.QuestCustomize, err =
		getI18N(db, worlddb.STRING_TEXT_TYPE_QUEST_CUSTOMIZE, questID)
	if err != nil && err != sql.ErrNoRows {
		return nil, err
	}
	questProto.QuestInfo, err = getQuestInfo(db, questID)
	if err != nil {
		return nil, err
	}
	questData, err := json.Marshal(
		fusion.MarshalEntityToInterface(&questProto, "json"))
	if err != nil {
		return nil, err
	}
	return questData, nil
}

func newQuestInstance(tx *sql.Tx, questName, questDesc string) (uint32, error) {
	questInfo := worlddb.QuestPrototype{}
	questID, err := fusion.SaveJsontableToDB(tx, &questInfo)
	if err != nil {
		return 0, err
	}
	err = setI18Ns(tx,
		worlddb.STRING_TEXT_TYPE_QUEST_NAME, questID, questName,
		worlddb.STRING_TEXT_TYPE_QUEST_DESC, questID, questDesc)
	if err != nil {
		return 0, err
	}
	return questID, nil
}

func copyQuestInstance(db *sql.DB, tx *sql.Tx, questID uint32) (uint32, error) {
	var questInfo *worlddb.QuestPrototype
	questInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(questInfo), "`questTypeID`=?", questID)
	if err != nil {
		return 0, err
	}
	if questInfoVals.Len() < 1 {
		return 0, sql.ErrNoRows
	}
	questInfo = questInfoVals.Index(0).Interface().(*worlddb.QuestPrototype)
	questInfo.QuestTypeID = 0
	ID, err := fusion.SaveJsontableToDB(tx, questInfo)
	if err != nil {
		return 0, err
	}
	err = copyI18Ns(db, tx,
		worlddb.STRING_TEXT_TYPE_QUEST_NAME, questID, ID,
		worlddb.STRING_TEXT_TYPE_QUEST_DESC, questID, ID,
		worlddb.STRING_TEXT_TYPE_QUEST_INTRO, questID, ID,
		worlddb.STRING_TEXT_TYPE_QUEST_DONE, questID, ID,
		worlddb.STRING_TEXT_TYPE_QUEST_NOT_DONE, questID, ID,
		worlddb.STRING_TEXT_TYPE_QUEST_CUSTOMIZE, questID, ID)
	if err != nil {
		return 0, err
	}
	return ID, nil
}

func deleteQuestInstance(tx *sql.Tx, questID uint32) error {
	_, err := tx.Exec(
		"DELETE FROM `quest_prototype` WHERE `questTypeID`=?", questID)
	if err != nil {
		return err
	}
	return nil
}

func saveQuestInstance(tx *sql.Tx, questProto *QuestPrototype) error {
	err := setI18Ns(tx,
		worlddb.STRING_TEXT_TYPE_QUEST_NAME,
		questProto.QuestInfo.QuestTypeID, questProto.QuestName,
		worlddb.STRING_TEXT_TYPE_QUEST_DESC,
		questProto.QuestInfo.QuestTypeID, questProto.QuestDesc,
		worlddb.STRING_TEXT_TYPE_QUEST_INTRO,
		questProto.QuestInfo.QuestTypeID, questProto.QuestIntro,
		worlddb.STRING_TEXT_TYPE_QUEST_DONE,
		questProto.QuestInfo.QuestTypeID, questProto.QuestDone,
		worlddb.STRING_TEXT_TYPE_QUEST_NOT_DONE,
		questProto.QuestInfo.QuestTypeID, questProto.QuestNotDone,
		worlddb.STRING_TEXT_TYPE_QUEST_CUSTOMIZE,
		questProto.QuestInfo.QuestTypeID, questProto.QuestCustomize)
	if err != nil {
		return err
	}
	_, err = fusion.SaveJsontableToDB(tx, questProto.QuestInfo)
	if err != nil {
		return err
	}
	return nil
}
